/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package util;

import java.awt.Point;
import java.util.*;
import minesweeper.MyButton;

/**
 *
 * @author CodeBlue
 */
public class GameUtility {

    // count flagged buttons on game
    public static int flagCount = 0;
    // singleton
    private static GameUtility utility = null;

    public static GameUtility getInstance() {
        return utility != null ? utility : (utility = new GameUtility());
    }

    // params:
    // list of components (can be cast to MyButton)
    // x,y: coordinate that is stored in a button
    private int getBombArround(List<MyButton> buttonList, int x, int y) {
        int count = 0;
        for (MyButton myBut : buttonList) {
            for (int i = -1; i <= 1; i++) {
                for (int j = -1; j <= 1; j++) {
                    if (myBut.getPoint().equals(new Point(x + i, y + j)) && myBut.getBombArround() == -1) {
                        count++;
                    }
                }
            }
        }
        return count;
    }

    // generate map to play
    public void generateMap(List<MyButton> buttonList, int allButtons) {
        Set bombIndexes = getBombIndexes(allButtons);
        for (Iterator it = bombIndexes.iterator(); it.hasNext();) {
            buttonList.get(Integer.valueOf(it.next().toString())).setBombArround(-1);
        }
        for (MyButton button : buttonList) {
            if (button.getBombArround() == -1) {
                continue;
            }
            int x = button.getPoint().x;
            int y = button.getPoint().y;
            button.setBombArround(getBombArround(buttonList, x, y));
        }
    }

    /*
     * Đây là cách xử lý thứ 1 - Sử dụng đệ quy
     */
    public void noBombClicked(MyButton btnClicked, List<MyButton> buttonList) {
        int bombArround = btnClicked.getBombArround();
        btnClicked.setEnabled(false);
        if (bombArround != 0) {
            btnClicked.setText(bombArround + "");
        } else {
            int x = btnClicked.getPoint().x;
            int y = btnClicked.getPoint().y;
            for (MyButton myButton : buttonList) {
                for (int i = -1; i <= 1; i++) {
                    for (int j = -1; j <= 1; j++) {
                        if (myButton.getPoint().equals(new Point(x + i, y + j)) && !(i == 0 && j == 0)) {
                            int bombs = myButton.getBombArround();
                            if (bombs != 0) {
                                myButton.setText(bombs + "");
                            }
                            if (bombs == 0 && myButton.isEnabled()) {
                                noBombClicked(myButton, buttonList);
                            }
                            myButton.setEnabled(false);
                        }
                    }
                }
            }
        }
    }

    /*
     * Đây là cách xử lý thứ 2 - Không sử dụng đệ quy
     */
    public void noBombClicked_method2(MyButton btnClicked, List<MyButton> buttonList) {
        int bombArround = btnClicked.getBombArround();
        btnClicked.setText(bombArround + "");
        btnClicked.setEnabled(false);
        if (bombArround == 0) {
            List<MyButton> noBombList = new LinkedList<MyButton>();
            noBombList.add(btnClicked);
            //List<Point> points = new LinkedList<Point>();
            //points.add(btnClicked.getPoint());
            while (!noBombList.isEmpty()) {
                List<MyButton> temp = new LinkedList<MyButton>();
                for (MyButton myBtn : noBombList) {
                    int x = myBtn.getPoint().x;
                    int y = myBtn.getPoint().y;
                    for (MyButton myButton : buttonList) {
                        for (int i = -1; i <= 1; i++) {
                            for (int j = -1; j <= 1; j++) {
                                if (myButton.getPoint().equals(new Point(x + i, y + j)) && !(i == 0 && j == 0)) {
                                    int bombs = myButton.getBombArround();
                                    myButton.setText(bombs + "");
                                    if (bombs == 0 && myButton.isEnabled()) {
//                                        boolean mark = false;
//                                        for (Point point : points) {
//                                            if (myButton.getPoint().equals(point)) {
//                                                mark = true;
//                                            }
//                                        }
//                                        if (!mark) {
                                        temp.add(myButton);
//                                            points.add(myButton.getPoint());
//                                        }
                                    }
                                    myButton.setEnabled(false);
                                }
                            }
                        }
                    }
                }
                noBombList.removeAll(noBombList);
                noBombList.addAll(temp);
            }
        }

    }

    // get number of bombs the game has
    public static int getBombCount(int allButtons) {
        int numOfBombs = allButtons / 5;
        if (!GameSettings.isDefaultBombSetup) {
            numOfBombs = GameSettings.NUM_OF_BOMBS;
        }
        return numOfBombs;
    }

    // get a set of indexes to setup buttons with bomb
    // The purpose of usage of Set is to get distinct items
    private Set getBombIndexes(int allButtons) {
        int numOfBombs = getBombCount(allButtons);
        Set bombIndexes = new HashSet();
        Random random = new Random();
        while (bombIndexes.size() != numOfBombs) {
            bombIndexes.add(getRandomInteger(0, allButtons - 1, random));
        }
        return bombIndexes;
    }

    // generate a random number
    private int getRandomInteger(int aStart, int aEnd, Random aRandom) {
        if (aStart > aEnd) {
            throw new IllegalArgumentException("Start cannot exceed End.");
        }
        //get the range, casting to long to avoid overflow problems
        long range = (long) aEnd - (long) aStart + 1;
        // compute a fraction of the range, 0 <= frac < range
        long fraction = (long) (range * aRandom.nextDouble());
        int randomNumber = (int) (fraction + aStart);
        return randomNumber;
    }

    // display all buttons with text or icon
    public void showAllButtons(List<MyButton> buttonList) {
        for (MyButton button : buttonList) {
            if (button.isEnabled()) {
                button.setEnabled(false);
                int bombArround = button.getBombArround();
                if (bombArround == -1) {
                    button.showBomb();
                } else if (bombArround == 0) {
                    button.setText("");
                } else {
                    button.setText(bombArround + "");
                }
            }
        }
    }

    // display all buttons with bomb (when player clicked on bomb)
    public void showAllBombs(List<MyButton> buttonList, MyButton clickedButton) {
        Point clickedPoint = clickedButton.getPoint();
        for (MyButton myButton : buttonList) {
            if (myButton.getBombArround() == -1 && !myButton.getPoint().equals(clickedPoint)) {
                myButton.showBomb();
            }
        }
    }

    // get number of buttons that are showing
    public int getButtonShowed(List<MyButton> buttonList) {
        int count = 0;
        for (MyButton myButton : buttonList) {
            if (!myButton.isEnabled()) {
                count++;
            }
        }
        return count;
    }
}
